//
// Created by 24319 on 2025/5/25.
//
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include "stm32f1xx_hal.h"
#include "UARTSendData.h"
#include "usart.h"
#include "../../User/Hardware/OLED.h"


char Serial_RxPackage[200];//存放收到的数据


void sendbyte(uint8_t byte)//发送一个字节
{
    HAL_UART_Transmit(&huart1,&byte,1,HAL_MAX_DELAY);
}
void sendarray(uint8_t *array,uint16_t Length)//发送一个数组
{
    for(uint16_t i=0;i<Length;i++){
        sendbyte(array[i]);
    }
}
void sendstring(char *String)//发送一个字符串
{
    for(uint16_t i=0;String[i]!='\0';i++)
    {
        sendbyte(String[i]);
    }
}


/**
 * @brief 通过UART发送AT指令到ESP8266模块
 * @param cmd 待发送的AT指令字符串（以'\r\n'结尾）
 */// 发送AT指令并等待响应
void ESP8266_SendCmd(char *cmd) {
    HAL_UART_Transmit(&huart1, (uint8_t*)cmd, strlen(cmd), 100);  // 发送指令
}

/**
 * @brief ESP8266模块初始化（配网、连接OneNet平台等）
 */
// ESP8266初始化流程
void ESP8266_Init(void) {

    memset(Serial_RxPackage, 0, 200);
    ESP8266_SendCmd("AT\r\n");
    HAL_Delay(1500);
    // while(CheckForOK(Serial_RxPackage, sizeof(Serial_RxPackage))==0);
    //sendstring("1_OK\r\n");//用于调试
    OLED_ShowString(3,3,"AT");
    memset(Serial_RxPackage, 0, 200);//清除wifi返回的指令


    // 2. 设置Station模式（1=Station, 2=SoftAP, 3=共存）
    ESP8266_SendCmd("AT+CWMODE=1\r\n");
    HAL_Delay(1500);
    // while(CheckForOK(Serial_RxPackage, sizeof(Serial_RxPackage))==0);
    //sendstring("2_OK\r\n");
    OLED_Clear();
    OLED_ShowString(3,3,"station");
    memset(Serial_RxPackage, 0, 200);//清除wifi返回的指令


    // 3. 启用DHCP（Station模式自动获取IP）
    ESP8266_SendCmd("AT+CWDHCP=1,1\r\n");
    HAL_Delay(1500);
    // while(CheckForOK(Serial_RxPackage, sizeof(Serial_RxPackage))==0);
    //sendstring("station_OK\r\n");
    OLED_Clear();
    OLED_ShowString(3,3,"DHCP");
    memset(Serial_RxPackage, 0, 200);//清除wifi返回的指令



    // 4. 连接WiFi（需替换为实际SSID和密码）
    char wifi_cmd[128];
    sprintf(wifi_cmd, "AT+CWJAP=\"%s\",\"%s\"\r\n", ESP8266_SSID, ESP8266_PASSWORD);
    ESP8266_SendCmd(wifi_cmd);
    HAL_Delay(5000);//延时久一点，便于顺利连上wifi
    //while(CheckForOK(Serial_RxPackage, sizeof(Serial_RxPackage))==0);
    //sendstring("WIFI_OK\r\n");
    OLED_Clear();
    OLED_ShowString(3,3,"wifi");
    memset(Serial_RxPackage, 0, 200);//清除wifi返回的指令


    //配置订阅设置
    ESP8266_SendCmd(ESP8266_ONENET_INFO);
    HAL_Delay(5000);//延时久一点，便于顺利连上ONENet平台
    //while(CheckForOK(Serial_RxPackage, sizeof(Serial_RxPackage))==0);
    //sendstring("d1_OK\r\n");
    OLED_Clear();
    OLED_ShowString(3,3," OneNet ");
    memset(Serial_RxPackage, 0, 200);//清除wifi返回的指令


    //连接MQTT
    ESP8266_SendCmd(ESP8266_MQTT_INFO);
    HAL_Delay(5000);
    //while(CheckForOK(Serial_RxPackage, sizeof(Serial_RxPackage))==0);
    //sendstring("Onenet_OK\r\n");
    OLED_Clear();
    OLED_ShowString(3,3,"MQTT");
    memset(Serial_RxPackage, 0, 200);


    //订阅设备数据
    ESP8266_SendCmd(ESP8266_MQTT_SUBSCRIBE);
    HAL_Delay(5000);
    //sendstring("SUB_OK\r\n");
    OLED_Clear();
    OLED_ShowString(3,3,"Esp Init OK");


}
/**
 * @brief 获取串口接收完成标志，并自动清零
 * @return 1-有新数据接收；0-无新数据
 */
uint8_t Serial_RxFlag;
uint8_t Serial_GetRxFlag(void)
{
    if(Serial_RxFlag==1)
    {
        Serial_RxFlag=0;
        return 1;
    }
    return 0;
}


/**
 * @brief UART接收事件回调函数（空闲中断处理）
 * @param huart UART句柄指针
 * @param Size 本次接收的字节数
 */
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
    if(huart==&huart1)
    {
        Serial_RxPackage[Size]='\0';
        Serial_RxFlag=1;
        HAL_UARTEx_ReceiveToIdle_IT(&huart1,Serial_RxPackage,sizeof (Serial_RxPackage));

    }
}


/**
 * 检查接收缓冲区中是否包含特定字符串"OK"
 * @param buffer 待检查的字符数组(通常为串口接收缓冲区)
 * @param length 数组有效数据长度
 * @return 包含返回1，不包含返回0
 */
uint8_t CheckForOK(uint8_t *buffer, uint16_t length) {
    // 遍历数组，注意防止越界(需要留出一个字符的检查空间)
    for (uint16_t i = 0; i < length - 1; i++) {
        // 检查当前字符是否为'O'
        if (buffer[i] == 'O') {
            // 如果是'O'，继续检查下一个字符是否为'K'
            if (buffer[i + 1] == 'K') {
                return 1;  // 找到"OK"字符串，返回成功
            }
        }
    }
    return 0;  // 遍历结束未找到，返回失败
}

char* generateMqttPublishCommand(float temp, bool ledState) {
    static char command[256];  // 静态缓冲区存储指令
    const char* template = "AT+MQTTPUB=0,\"$sys/3h7XtWS80P/d1/thing/property/post\",\"{\\\"id\\\":\\\"123\\\"\\,\\\"params\\\":{\\\"temp\\\":{\\\"value\\\":%.1f\\}\\,\\\"LEDState\\\":{\\\"value\\\":%s}}}\",0,0\r\n";

    // 根据LED状态选择true/false字符串
    const char* ledStr = ledState ? "true" : "false";

    // 格式化字符串
    snprintf(command, sizeof(command), template, temp, ledStr);
    return command;
}








